package com.google.ideas.MobileMeme.meme;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

//import org.apache.commons.codec.digest.DigestUtils;

/* NOTES:
 * MessageDigest can run the hash for me.  I want SHA-2.  
 * Lookup SQLite types, find a better type for both the hash and the image
 * The ImageStore will have to be used as one provider within an ImageSource type, which also includes the pictures/ folder and camera.
 *   An option for scaling the images is necessary.
 * The pictures/ folder importer is a great way to get this thing seeded.  Perhaps pull out of web browsers as well.
 * We'll need a camera intent (?) to get here as well.
 * Another hierarchy of layout options will be needed -- really, just lines, perhaps a set of segments with an algorithm for generating them for a given image?
 *   That way, I can have a border all the way around.  The path will need text direction, but that should be straightforward.
 */
public class ImageStore extends SQLiteOpenHelper {

	private static final int DATABASE_VERSION = 2;
	private static final int MAX_IMAGE_WIDTH = 720;
	private static final String DATABASE_NAME = "MemeImageStore.db";
	private static final String DICTIONARY_TABLE_NAME = "Images";
	private static final String DICTIONARY_TABLE_CREATE = "CREATE TABLE "
			+ DICTIONARY_TABLE_NAME + " ( hash TEXT, name TEXT, "
			+ "image BLOB, lastused DATE);";
	
	public ImageStore(Context context) {
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(DICTIONARY_TABLE_CREATE);		
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		if (oldVersion != DATABASE_VERSION) {
			db.execSQL("DROP TABLE " + DICTIONARY_TABLE_NAME);
			onCreate(db);
		}
	}
	
	public BaseImage lookupImage(SQLiteDatabase db, String hash) {
		final String[] cols = {"name, image"};
		final String[] vals = {hash};
		Cursor ret = db.query(DICTIONARY_TABLE_NAME, cols, "hash=?", vals, null, null, null, null);
		switch (ret.getCount()) {
		case 1: {
			String nm = ret.getString(0);
			byte[] image_blob = ret.getBlob(1);
			return new BaseImage(
					nm, BitmapFactory.decodeByteArray(image_blob, 0, 
							image_blob.length, null), hash);
		} 
		default:
			Log.i(DICTIONARY_TABLE_NAME, "Found " + ret.getCount() + " results, should be 0-1.");
		case 0: {
			return null;
		}	
		}
	}
		
	public boolean pingImage(SQLiteDatabase db, String hash) {
		ContentValues vals = new ContentValues();
		vals.put("lastused", (new Date()).getTime());
		return db.update(DICTIONARY_TABLE_NAME, vals, "hash=?", new String[]{hash}) > 0;	
	}
	
	private String calcHash(byte[] blob) {
		MessageDigest digest;
	    try {
	        digest = MessageDigest.getInstance("SHA-256");
	        digest.update(blob,0,blob.length);
	        return new BigInteger(1, digest.digest()).toString(16);
	    } 
	    catch (NoSuchAlgorithmException e) {
	        e.printStackTrace();
	    }
	    return "";
	}
	
	/**
	 * Save a BaseImage to our store.
	 * @param db
	 * @param image The BaseImage to save.  Its hash need not be calculated yet, we'll do that.
	 * @return null if the save failed, or the hash String
	 */
	public String saveImage(SQLiteDatabase db, BaseImage image) {
		Bitmap img = image.image();
		// resize the image !  Otherwise it can be too big for the screen.
		if (img.getWidth() > MAX_IMAGE_WIDTH) {
		  double scale_factor = ((double) MAX_IMAGE_WIDTH) / img.getWidth();
		  img = Bitmap.createScaledBitmap(img, MAX_IMAGE_WIDTH, 
		      (int) (img.getHeight() * scale_factor), true);
		}
		int size = img.getWidth() * img.getHeight();
		ByteArrayOutputStream out = new ByteArrayOutputStream(size);
		img.compress(Bitmap.CompressFormat.JPEG, 95, out);
		byte[] image_blob = out.toByteArray();
		String hash = calcHash(image_blob);
		ContentValues vals = new ContentValues();
		vals.put("name", image.getName());
		vals.put("image", image_blob);
		vals.put("hash", hash);
		vals.put("lastused", (new Date()).getTime());
		db.insert(DICTIONARY_TABLE_NAME, null, vals);
		return hash;
	}
	
	public List<BaseImage> allImages(SQLiteDatabase db) {
		List<BaseImage> results = new ArrayList<BaseImage>();
		final String[] cols = {"name", "image", "hash"};
		Cursor ret = db.query(DICTIONARY_TABLE_NAME, cols, null, null, null, null, "lastused", null);
		Log.d("image_store", "Got " + ret.getCount() + " items back");
		ret.moveToFirst();
		boolean cont = ret.getCount() > 0;
		while (cont) {
			byte[] image_blob = ret.getBlob(1);
			results.add(new BaseImage(ret.getString(0), 
					BitmapFactory.decodeByteArray(image_blob, 0, 
							image_blob.length, null), ret.getString(2)));
			cont = ret.moveToNext();
		}
		return results;
	}

}
